home *** CD-ROM | disk | FTP | other *** search
/ Cubase Magazine 32 / Issue #32.iso / 3-TUTORIAL / TRIANTI / convoluzione / loadwave.c < prev    next >
C/C++ Source or Header  |  2001-02-18  |  6KB  |  226 lines

  1. /*
  2.  
  3.             Lettore di file wave
  4.             (C)2000 - 2001 Aldo Trianti 
  5.  
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include "wavereader.h"
  10.  
  11. static int TrovaChunk (FILE* file, ChunkInfo* parentChunk, ChunkInfo* info, unsigned long tipo_chunk);
  12. static void s2f (short* int_buffer, float* float_buffer, unsigned int numeroCampioni);
  13.  
  14.  
  15. WaveFileDirect* WFD_ApriWave (char *nome_file)
  16. {
  17.     int retCode;    
  18.     RiffChunk ckRiff;
  19.     ChunkInfo ckFormat;
  20.     WaveFormat wf;    
  21.     ChunkInfo ckData;    
  22.     unsigned long tipo_file; /* RIFF */    
  23.     WaveFileDirect* pWaveFile = NULL;
  24.     FILE* file = NULL;
  25.     
  26.     file = fopen (nome_file, "rb"); /* apre il file in lettura */
  27.     if (file == NULL) goto error;
  28.  
  29.     /* legge il chunk iniziale */
  30.     retCode = fread(&ckRiff, sizeof(RiffChunk), 1, file);
  31.     if (retCode != 1) goto error;
  32.  
  33.     /* Procede solo se il file Φ di tipo RIFF */
  34.     if (ckRiff.id != RIFF_CHUNK) goto error;
  35.  
  36.     /* ed il tipo di dati deve essere WAVE */    
  37.     retCode = fread (&tipo_file, sizeof(unsigned long), 1, file);
  38.     if (retCode != 1) goto error;
  39.     if (tipo_file != TYPE_WAVE) goto error;
  40.  
  41.     /* ora troviamo il chunk che descrive il formato del file wave (numero di
  42.        canali, bit e frequenza di campionamento */
  43.     retCode = TrovaChunk (file, &ckRiff, &ckFormat, FMT__CHUNK);
  44.     if (retCode != 1) goto error;
  45.  
  46.     /* leggiamo il formato del file wave */
  47.     retCode = fread (&wf, sizeof wf, 1, file);
  48.     if (retCode != 1) goto error;
  49.  
  50.     /* controllo formato file */
  51.     if (wf.wFormatTag != 1) /* campioni interi */        
  52.         goto error; /* non supportiamo altri formati... */
  53.  
  54.     if (wf.wBitsPerSample != 16) /* solo file a 16 bit */
  55.         goto error;
  56.  
  57.     if (wf.nChannels > 2) /* mono o stereo. altri formati non supportati */
  58.         goto error;    
  59.  
  60.     /* passiamo ora al chunk che contiene i dati */
  61.     retCode = TrovaChunk (file, &ckRiff, &ckData, DATA_CHUNK);
  62.     if (retCode != 1) goto error;
  63.  
  64.     pWaveFile = malloc(sizeof(WaveFileDirect));
  65.     pWaveFile->file = file;
  66.     pWaveFile->nChannels = wf.nChannels;
  67.     pWaveFile->sampleRate = wf.nSamplesPerSec;
  68.     pWaveFile->bitPerSample = wf.wBitsPerSample;
  69.     pWaveFile->cbBlockAlign = wf.nBlockAlign;
  70.  
  71.     pWaveFile->nSamples = ckData.chunk.cbSize / wf.nBlockAlign;
  72.     pWaveFile->nSamplePosition = 0;
  73.     pWaveFile->pcmDataOffset = ftell(file);    
  74.  
  75.     return pWaveFile;
  76.  
  77. error:
  78.  
  79.     if (NULL != file) fclose(file);
  80.     if (NULL != pWaveFile) free(pWaveFile);
  81.  
  82.     return NULL; /* oops... non abbiamo trovato il chunk, 
  83.                     o qualcosa Φ andato storto.          */
  84. }
  85.  
  86. int WFD_Chiudi(WaveFileDirect *wfd)
  87. {
  88.     if (NULL != wfd->file) fclose(wfd->file);
  89.     if (NULL != wfd) free(wfd);
  90.     return 1;
  91. }
  92.  
  93. int WFD_Posiziona (WaveFileDirect *wfd, int numeroCampione)
  94. {
  95.     if (numeroCampione >= 0 && numeroCampione < wfd->nSamples)    
  96.         wfd->nSamplePosition = numeroCampione;    
  97.  
  98.     return wfd->nSamplePosition;
  99. }
  100.  
  101. int WFD_Leggi (WaveFileDirect *wfd, float *buffer, int numeroCampioni)
  102. {
  103.     int check;
  104.     int disk_offset = wfd->pcmDataOffset + 
  105.                       wfd->nSamplePosition * wfd->cbBlockAlign;
  106.  
  107.     check = fseek (wfd->file, disk_offset, SEEK_SET);
  108.     if (check == 0) /* Ok! */
  109.     {        
  110.         short temp[1024]; /* legge 1024 campioni alla volta dal file */
  111.         int campioniTotaliDaLeggere = numeroCampioni * wfd->nChannels;
  112.         float scala = 1.0F/32768.0F;
  113.         check = 0;
  114.  
  115.         while (campioniTotaliDaLeggere != 0)
  116.         {
  117.             int k;
  118.  
  119.             /* legge 1024 (o meno) campioni alla volta */
  120.             int daLeggere = campioniTotaliDaLeggere;
  121.             if (daLeggere > 1024) daLeggere = 1024;            
  122.             fread(temp, sizeof(short), daLeggere, wfd->file);
  123.  
  124.             /* converte da intero a float */
  125.             for (k = 0; k < daLeggere; ++k)            
  126.                 buffer[k] = temp[k] * scala;            
  127.             
  128.             buffer += daLeggere;
  129.             check += daLeggere;
  130.             campioniTotaliDaLeggere -= daLeggere;
  131.         }            
  132.     }
  133.     else
  134.         check = 0;
  135.  
  136.     return check;    
  137. }
  138.  
  139. int WFD_LeggiCampione(WaveFileDirect *wfd, float* buffer)
  140. {    
  141.     static float scale = 1.0F / 32768.0F;
  142.     int ok = 0;
  143.     
  144.     if (wfd->nChannels == 1)
  145.     {
  146.         short temp;
  147.         if (fread(&temp, 2, 1, wfd->file) != 0)
  148.         {
  149.             *buffer = temp * scale;
  150.             ok = 1;
  151.         }
  152.     }
  153.     else
  154.     {
  155.         short temp[2];
  156.         if (fread(&temp, 1, 4, wfd->file) == 4)
  157.         {
  158.             buffer[0] = temp[0] * scale;
  159.             buffer[1] = temp[1] * scale;
  160.             ok = 1;
  161.         }
  162.     }
  163.  
  164.     return ok;
  165. }
  166.  
  167. /*-------------------------------------------------------------------------*/
  168. static int TrovaChunk (FILE* file, 
  169.                        ChunkInfo* parentChunk, 
  170.                        ChunkInfo* info, 
  171.                        unsigned long tipo_chunk)
  172. {
  173.     long retCode;    
  174.     unsigned long dimensioneChunk;
  175.     
  176.     /* dimensione, in byte dei dati contenuti nel chunk */
  177.     unsigned long byteRimanenti = parentChunk->chunk.cbSize;
  178.  
  179.     /* posiziona il file esattamente alla fine del descrittore 
  180.        del chunk */
  181.     if (parentChunk->chunk.id == RIFF_CHUNK)
  182.         retCode = fseek(file, 12, SEEK_SET);
  183.     else
  184.         retCode = fseek(file, parentChunk->offset, SEEK_SET);
  185.  
  186.     if (retCode) goto error;
  187.     
  188.     while (byteRimanenti > 0)
  189.     {
  190.         /* legge il descrittore del chunk */
  191.         retCode = fread (&(info->chunk), sizeof(RiffChunk), 1, file);
  192.         if (retCode != 1) goto error;
  193.  
  194.         /* controlla se Φ del tipo specificato... */
  195.         if (info->chunk.id == tipo_chunk)             
  196.         {        
  197.             info->offset = ftell(file); /* trovato! */
  198.             return 1;
  199.         }
  200.  
  201.         /* calcola la dimensione del chunk */
  202.         dimensioneChunk = info->chunk.cbSize;
  203.         
  204.         /* i numeri di byte devono essere sempre pari.
  205.            Se non lo sono aggiungiamo 1 alla dimensione del
  206.            chunk. */
  207.         if (dimensioneChunk & 1) ++dimensioneChunk;
  208.  
  209.         /* aggiorna i byte rimanenti */
  210.         byteRimanenti -= dimensioneChunk + sizeof(RiffChunk);
  211.  
  212.         /* avanza nel file saltando i dati presenti nel chunk */
  213.         retCode = fseek (file, dimensioneChunk, SEEK_CUR);
  214.         if (retCode) goto error;
  215.  
  216.         /* ora, essendo il puntatore del file posizionato all'inizio 
  217.            del prossimo chunk, possiamo ripetere l'operazione... */
  218.     }
  219.  
  220. error:
  221.  
  222.     return 0; /* oops... non abbiamo trovato il chunk, 
  223.                  o qualcosa Φ andato storto.          */
  224. }
  225.  
  226.